/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package com.helwen.restaurantbooking.bo.boimpl;

import com.helwen.restaurantbooking.bo.IBookingBo;
import com.helwen.restaurantbooking.datalayer.dao.IBookingDao;
import com.helwen.restaurantbooking.datalayer.dao.ITableDao;
import com.helwen.restaurantbooking.datalayer.entities.TblBooking;
import com.helwen.restaurantbooking.datalayer.entities.TblTable;
import com.helwen.restaurantbooking.helper.BeanManagerHelper;
import com.toedter.calendar.JDateChooser;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;
import javax.swing.JComboBox;
import javax.swing.JTextField;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

/**
 *
 * @author Nghiata
 */
@Service("bookingBo")
@Transactional(propagation = Propagation.REQUIRED, readOnly = true, isolation = Isolation.DEFAULT)
public class BookingBoImpl implements IBookingBo {

    @Autowired
    private IBookingDao bookingDao;
    @Autowired
    private ITableDao tableDao;

    public IBookingDao getBookingDao() {
        return bookingDao;
    }

    public void setBookingDao(IBookingDao bookingDao) {
        this.bookingDao = bookingDao;
    }

    public List<TblBooking> getAllBookingInfo() {
        return bookingDao.getAllBookingInfo();
    }

    public List<TblBooking> getBookingByTable(Integer tableNumber) {
        return null;
    }

    public TblBooking getBookingActiveOnTable(Integer tableNumber) {
        return null;
    }

    @Transactional(readOnly = false)
    public void saveOrUpdate(TblBooking tblBooking) {
        bookingDao.saveOrUpdate(tblBooking);
    }

    @Transactional(readOnly = false)
    public void saveOrUpdate(Integer id, JTextField txtName, JTextField txtContact, JDateChooser dcDate, JComboBox cbxTime, JComboBox cbxStaffName, JComboBox cbxArea, JComboBox cbxTableNumber, JTextField txtNumberOfPack, JTextField txtRemarks, Short status) {

        TblBooking tblBooking = new TblBooking();
        if (id != null) {
            tblBooking = bookingDao.getBookingById(id);
        }
        tblBooking.setCustomerName(txtName.getText());
        tblBooking.setContact(txtContact.getText());
        tblBooking.setReservationDate(dcDate.getDate());
        Short reservationTime = 0;
        String time = cbxTime.getSelectedItem().toString();

        if (time.endsWith("am") && !time.startsWith("0")) {
            time = time.replaceAll(" am", "");
            time = time.replaceAll(" am", "");
            reservationTime = new Short(time);
        } else if (time.endsWith("pm")) {
            time = time.replaceAll(" pm", "");
            Integer inte = new Integer(time) + 12;
            reservationTime = new Short(inte + "");
        }
        tblBooking.setReservationTime(reservationTime);

        tblBooking.setStaffName(cbxStaffName.getSelectedItem().toString());

        Integer tableNumber = 1;
        String area = cbxArea.getSelectedItem().toString();
        if (area.equals("Non-Smoking Room")) {
            tableNumber = new Integer(cbxTableNumber.getSelectedItem().toString());
        } else {
            tableNumber = new Integer(cbxTableNumber.getSelectedItem().toString()) + 5;
        }

        tblBooking.setRemarks(txtRemarks.getText());
        Short numberOfPackage = new Short(txtNumberOfPack.getText());
        if (numberOfPackage <= 5) {

            TblTable tblTable = tableDao.getTableByNumber(tableNumber);
            tblBooking.setTblTable(tblTable);
            tblBooking.setNumberOfPack(new Short(txtNumberOfPack.getText()));

            if (id == null) {
                tblBooking.setStatus(status);
            }
            bookingDao.saveOrUpdate(tblBooking);
        } else {
            Date reservationDate = dcDate.getDate();
            reservationDate.setHours(0);
            reservationDate.setSeconds(0);
            reservationDate.setMinutes(0);
            Map<TblTable, Integer> map = new HashMap<TblTable, Integer>();
            if (area.equals("Non-Smoking Room")) {
                map = getTablesAbleToReserve(false, true, tableNumber, reservationDate, reservationTime, new Integer(numberOfPackage));
            } else if (area.equals("Smoking Room")) {
                map = getTablesAbleToReserve(false, false, tableNumber, reservationDate, reservationTime, new Integer(numberOfPackage));
            } else {
                map = getTablesAbleToReserve(true, true, tableNumber, reservationDate, reservationTime, new Integer(numberOfPackage));
            }

            List<TblBooking> bookingListNeedInsert = new ArrayList<TblBooking>();
            for (Map.Entry<TblTable, Integer> entry : map.entrySet()) {
                TblTable tblTable = entry.getKey();
                Integer integer = entry.getValue();
                TblBooking tbl = new TblBooking();
                tbl.setCustomerName(tblBooking.getCustomerName());
                tbl.setContact(tblBooking.getContact());
                tbl.setRemarks(tblBooking.getRemarks());
                tbl.setStaffName(tblBooking.getStaffName());
                tbl.setReservationDate(reservationDate);
                tbl.setReservationTime(reservationTime);
                tbl.setTblTable(tblTable);
                tbl.setNumberOfPack(new Short(integer + ""));
                if (id == null) {
                    tbl.setStatus(status);
                }
                bookingListNeedInsert.add(tbl);
            }
            bookingDao.bulkInsert(bookingListNeedInsert);

        }
    }

    public Object[][] getDateModel(String searchName, String searchContact, String columnName, String sort) {
        List<TblBooking> tblBookings = new ArrayList<TblBooking>();
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("EEE , dd MMM yyyy");
        if (searchName.trim().equals("") && searchContact.trim().equals("")) {
            if (columnName.equals("")) {
                tblBookings = bookingDao.getAllBookingInfo();
            } else {
                tblBookings = bookingDao.getAllBookingInfoOrderby(columnName, sort);
            }
        } else {
            if (columnName.equals("")) {
                tblBookings = bookingDao.getBookingByCriteria(searchName, searchContact);
            } else {
                tblBookings = bookingDao.getBookingByCriteriaOrderBy(searchName, searchContact, columnName, sort);
            }
        }
        Object[][] dataModel = new Object[tblBookings.size()][10];
        for (int i = 0; i < tblBookings.size(); i++) {
            TblBooking tblBooking = tblBookings.get(i);
            dataModel[i][0] = tblBooking.getCustomerName();
            dataModel[i][1] = tblBooking.getContact();



            dataModel[i][2] = simpleDateFormat.format(tblBooking.getReservationDate());



            String reservationTime = "";
            Short time = tblBooking.getReservationTime();
            reservationTime = time + ":00";
            dataModel[i][3] = reservationTime;
            dataModel[i][4] = tblBooking.getStaffName();
            dataModel[i][5] = tblBooking.getTblTable().getArea();
            Integer tablenumber = tblBooking.getTblTable().getTableNumber();
            if (tablenumber > 5) {
                tablenumber -= 5;
            }
            dataModel[i][6] = tablenumber;
            dataModel[i][7] = tblBooking.getNumberOfPack();
            dataModel[i][8] = tblBooking.getRemarks();


            if (tblBooking.getStatus() == 0) {
                dataModel[i][9] = "Waiting";
            } else if (tblBooking.getStatus() == 1) {
                dataModel[i][9] = "Running";
            } else if (tblBooking.getStatus() == 2) {
                dataModel[i][9] = "Completed";
            } else {
                dataModel[i][9] = "Incompleted";
            }
        }
        return dataModel;
    }

    public List<String> validateInputform(Integer id, JTextField txtName, JTextField txtContact, JDateChooser dcDate, JComboBox cbxTime, JComboBox cbxArea, JComboBox cbxTableNumber, JTextField txtNumberOfPack) {

        List<String> error = new ArrayList<String>();
        String area = cbxArea.getSelectedItem().toString();
        Integer tableNumber = new Integer(cbxTableNumber.getSelectedItem().toString());
        if (!area.equals("Non-Smoking Room")) {
            tableNumber -= 5;
        }
        Date reservationDate = dcDate.getDate();
        reservationDate.setHours(0);
        reservationDate.setSeconds(0);
        reservationDate.setMinutes(0);
        Short reservationTime = 0;
        String time = cbxTime.getSelectedItem().toString();

        if (time.endsWith("am") && !time.startsWith("0")) {
            time = time.replaceAll(" am", "");

            time = time.replaceAll(" am", "");
            reservationTime = new Short(time);
        } else if (time.endsWith("pm")) {
            time = time.replaceAll(" pm", "");
            Integer inte = new Integer(time) + 12;
            reservationTime = new Short(inte + "");
        }

        if (txtName.getText().isEmpty()) {
            error.add("Name of customer must input");
        }
        if (txtContact.getText().isEmpty()) {
            error.add("Contact of customer must input");
        }
        boolean isBooked = false;
        List<TblBooking> tblBookings = bookingDao.getBookingByNumberDateTime(tableNumber, reservationDate, reservationTime);
        if (tblBookings.size() > 0) {

            if (tblBookings.get(0).getId() != id && (tblBookings.get(0).getStatus() == 1 || tblBookings.get(0).getStatus() == 0)) {
                error.add("Sorry table have bean reserved on " + reservationDate.toString() + " " + reservationTime + ", please choose another table.");
                isBooked = true;
            }
        }
        List<TblBooking> reservedBeforeBookings = bookingDao.getBookingByNumberDateTime(tableNumber, reservationDate, ++reservationTime);
        if (reservedBeforeBookings.size() > 0) {
            if (tblBookings.get(0).getId() != id && (tblBookings.get(0).getStatus() == 1 || tblBookings.get(0).getStatus() == 0)) {
                error.add("Sorry table have bean reserved on " + reservationDate.toString() + " " + reservationTime + ", please choose another table.");
                isBooked = true;
            }
        }

        reservationTime--;

        String numberOfPack = txtNumberOfPack.getText();
        try {
            int number = Integer.parseInt(numberOfPack);
            int vacantTables = 0;
            if (area.equals("Non-Smoking Room")) {
                vacantTables = getAvailableTables(false, true, tableNumber, reservationDate, reservationTime).size();
                if (!isBooked) {
                    vacantTables++;
                }
            } else if (area.equals("Smoking Room")) {
                vacantTables = getAvailableTables(false, false, tableNumber, reservationDate, reservationTime).size();
                if (!isBooked) {
                    vacantTables++;
                }
            } else {
                vacantTables = getAvailableTables(true, true, tableNumber, reservationDate, reservationTime).size();
            }

            if (number > vacantTables * 5) {
                String ar = "";
                if (!area.equals("Non-Smoking Room") && !area.equals("Smoking Room")) {
                    ar = "[" + area + "]";
                }
                error.add(ar + "On " + reservationTime + " h" + ", " + reservationDate + ", has " + vacantTables + " vacant tables" + " and maximum is " + vacantTables * 5 + " positions able to reserve!");
            }

        } catch (Exception e) {
            error.add("Number of pack must be integer");
        }

        return error;
    }

    @Transactional(readOnly = false)
    public void inserBooking(JTextField txtName, JTextField txtContact, JDateChooser dcDate, Short cbxTime, JComboBox cbxStaffName, String area, Integer number, JTextField txtNumberOfPack) {
        TblBooking tblBooking = new TblBooking();
        tblBooking.setCustomerName(txtName.getText());
        tblBooking.setContact(txtContact.getText());
        tblBooking.setReservationDate(dcDate.getDate());
        Short reservationTime = (short) (new Date().getHours());
        tblBooking.setReservationTime(reservationTime);
        tblBooking.setStaffName(cbxStaffName.getSelectedItem().toString());
        Integer tableNumber = 1;
        tableNumber = number;
        Short numberOfPack = new Short(txtNumberOfPack.getText());
        if (numberOfPack <= 5) {
            TblTable tblTable = tableDao.getTableByNumber(tableNumber);
            tblTable.setStatus(new Short("2"));
            tblBooking.setTblTable(tblTable);
            tblBooking.setNumberOfPack(new Short(txtNumberOfPack.getText()));
            tblBooking.setStatus(new Short("1"));
            bookingDao.saveOrUpdate(tblBooking);
        } else {
            Date reservationDate = dcDate.getDate();
            reservationDate.setHours(0);
            reservationDate.setSeconds(0);
            reservationDate.setMinutes(0);
            Map<TblTable, Integer> map = new HashMap<TblTable, Integer>();
            if (area.equals("Non-Smoking Room")) {
                map = getTablesAbleToReserve(false, true, tableNumber, reservationDate, reservationTime, new Integer(numberOfPack));
            } else {
                map = getTablesAbleToReserve(false, false, tableNumber, reservationDate, reservationTime, new Integer(numberOfPack));
            }

            List<TblBooking> bookingListNeedInsert = new ArrayList<TblBooking>();
            for (Map.Entry<TblTable, Integer> entry : map.entrySet()) {
                TblTable tblTable = entry.getKey();
                tblTable.setStatus((short) 2);
                Integer integer = entry.getValue();
                TblBooking tbl = new TblBooking();
                tbl.setCustomerName(tblBooking.getCustomerName());
                tbl.setContact(tblBooking.getContact());
                tbl.setRemarks(tblBooking.getRemarks());
                tbl.setStaffName(tblBooking.getStaffName());
                tbl.setReservationDate(reservationDate);
                tbl.setReservationTime(reservationTime);
                tbl.setTblTable(tblTable);
                tbl.setNumberOfPack(new Short(integer + ""));

                tbl.setStatus((short) 1);

                bookingListNeedInsert.add(tbl);
            }
            bookingDao.bulkInsert(bookingListNeedInsert);
        }


    }

    public List<String> validateBookForm(JTextField txtName, JTextField txtContact, JComboBox cbxTableNumber, JComboBox cbxArea, JTextField txtNumberOfPack) {
        List<String> error = new ArrayList<String>();
        if (txtName.getText().isEmpty()) {
            error.add("Name of customer must input");
        }
        if (txtContact.getText().isEmpty()) {
            error.add("Contact of customer must input");
        }
        boolean isNonSmokingRoom = cbxArea.getSelectedItem().toString().equals("Non-Smoking Room") ? true : false;
        String numberOfPack = txtNumberOfPack.getText();
        try {
            int number = Integer.parseInt(numberOfPack);
            int vacantTables = 0;
            Date reservationDate = new Date();
            Short reservationTime = (short) (new Date().getHours());
            reservationDate.setHours(0);
            reservationDate.setSeconds(0);
            reservationDate.setMinutes(0);
            vacantTables = getAvailableTables(false, isNonSmokingRoom, new Integer(cbxTableNumber.getSelectedItem().toString()), reservationDate, reservationTime).size();

            if (number > (vacantTables + 1) * 5) {
                String ar = "";
                ar = isNonSmokingRoom ? "[Non-Smoking Room]" : "[Smoking Room]";
                error.add(ar + "On " + reservationDate + ", has " + (vacantTables + 1) + " vacant tables" + " and maximum is " + (vacantTables + 1) * 5 + " positions able to reserve!");
            }

        } catch (Exception e) {
            error.add("Number of pack must be integer");
        }
        return error;
    }

    public List<TblBooking> getWaitingBooking() {
        return bookingDao.getWaitingBooking();
    }

    @Transactional(readOnly = false)
    public void clearHistory() {
        bookingDao.deleteAll();
        tableDao.resetAll();
    }

    public List<TblTable> getAvailableTables(boolean isAll, boolean isNonSmokingArea, Integer selectedNumber, Date reservationDate, Short reservationTime) {
        reservationDate.setHours(0);
        reservationDate.setMinutes(0);
        reservationDate.setSeconds(0);
        List<TblTable> tblTables = new ArrayList<TblTable>();
        if (isAll) {
            tblTables = tableDao.getAllTable();
        } else {
            tblTables = tableDao.getTableByArea(isNonSmokingArea);
            tblTables.remove(tableDao.getTableByNumber(selectedNumber));
        }

        List<TblTable> availableTables = new ArrayList<TblTable>();
        for (TblTable tblTable : tblTables) {
            boolean flag1 = true;
            boolean flag2 = true;
            if (tblTable.getStatus() != 2) {
                Integer tableNumber = tblTable.getTableNumber();
                List<TblBooking> tblBookings = bookingDao.getBookingByNumberDateTime(tableNumber, reservationDate, reservationTime);
                if (tblBookings.size() > 0) {

                    if ((tblBookings.get(0).getStatus() == 1 || tblBookings.get(0).getStatus() == 0)) {
                        flag1 = false;
                    }
                }
                Short nextHour = ++reservationTime;
                List<TblBooking> reservedBeforeBookings = bookingDao.getBookingByNumberDateTime(tableNumber, reservationDate, nextHour);
                if (reservedBeforeBookings.size() > 0) {
                    if ((tblBookings.get(0).getStatus() == 1 || tblBookings.get(0).getStatus() == 0)) {
                        flag2 = false;
                    }
                }
                --reservationTime;
            } else {
                flag1 = false;
                flag2 = false;
            }
            if (flag1 && flag2) {
                availableTables.add(tblTable);
            }
        }
        return availableTables;
    }

    public Map<TblTable, Integer> getTablesAbleToReserve(boolean isAll, boolean isNonSmokingArea, Integer selectedNumber, Date reservationDate, Short reservationTime, Integer numberOfPack) {
        Map<TblTable, Integer> map = new HashMap<TblTable, Integer>();
        List<TblTable> availableTables = getAvailableTables(isAll, isNonSmokingArea, selectedNumber, reservationDate, reservationTime);
        int numberTableNeeded = numberOfPack / 5;
        if (numberOfPack % 5 > 0) {
            numberTableNeeded++;
        }


        if (!isAll) {
            map.put(tableDao.getTableByNumber(selectedNumber), 5);
            numberTableNeeded--;
            numberOfPack -= 5;
        }
        List<TblTable> radomTable = getRadom(numberTableNeeded, availableTables);
        for (int i = 0; i < numberTableNeeded; i++) {
            int peoplePerTable = 5;
            if (numberOfPack >= (i + 1) * 5) {
                peoplePerTable = 5;
            } else {
                peoplePerTable = numberOfPack % 5;
            }
            map.put(radomTable.get(i), peoplePerTable);
        }
        return map;
    }

    private List<TblTable> getRadom(Integer numberOfRadoms, List<TblTable> tables) {
        List<TblTable> randomTable = new ArrayList<TblTable>();
        Map<Integer, TblTable> result = new HashMap<Integer, TblTable>();
        Random random = new Random();
        int range = tables.size();
        Integer radomindex = 0;
        while (result.size() < numberOfRadoms) {
            radomindex = random.nextInt(range);
            if (!result.containsKey(tables.get(radomindex).getTableNumber())) {
                result.put(radomindex, tables.get(radomindex));
            }
        }

        for (Map.Entry<Integer, TblTable> entry : result.entrySet()) {
            randomTable.add(entry.getValue());

        }
        return randomTable;

    }

    public static void main(String[] args) {
        IBookingBo bookingBo = (IBookingBo) BeanManagerHelper.getBean("bookingBo");
        List<TblTable> list = bookingBo.getAvailableTables(false, false, 9, new Date(), (short) 22);
        for (TblTable tblTable : list) {
            System.out.println(tblTable.getTableNumber() + ":" + tblTable.getStatus() + ":");
        }
//        Map<TblTable, Integer> map = bookingBo.getTablesAbleToReserve(false, true, 4, new Date(), (short) 22, 8);
//        for (Map.Entry<TblTable, Integer> entry : map.entrySet()) {
//            TblTable tblTable = entry.getKey();
//            Integer integer = entry.getValue();
//            System.out.println(tblTable.getTableNumber() + ":" + tblTable.getStatus() + ":" + integer);
//
//        }
    }
}
